﻿using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Effects;
using Microsoft.Graphics.Canvas.Geometry;
using Microsoft.Graphics.Canvas.UI.Xaml;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
using Windows.Web.Http;
using 纸片人.AttributeUsageFloder;

// https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板

namespace 纸片人.PageViews
{

    [LastModified("2022-5-12", "create PerlinNoisePage.xaml")]
    [PageType("cpu", "噪声")]
    /// <summary>
    /// 可用于自身或导航至 Frame 内部的空白页。
    /// </summary>
    public sealed partial class PerlinNoisePage : Page
    {
        Perlin p = new Perlin();

        AnimationType type = new AnimationType();


        List<Puzzle> listPuzzle = new List<Puzzle>();


        Perlin perlin = new Perlin();



        List<CanvasRenderTarget> listRender = new List<CanvasRenderTarget>();


        CanvasRenderTarget sunFireRender;

        CanvasRenderTarget ribbonRender;

        int ribbonFrameCount = 0;

        const int particleNumber = 20000;
        Point[] pos = new Point[particleNumber];
        double fliudTime;

        double time = 0;

        DispatcherTimer timer = new DispatcherTimer();


        CanvasRenderTarget circleRender;
        CanvasRenderTarget fliudRender;


        int sx = 0;
        int ex = 1000;

        double maxWidth = 0;
        double currentX = 0;


        double cx = 0, cy = 0;

        public PerlinNoisePage()
        {
            this.InitializeComponent();


            canvas.CreateResources += Canvas_CreateResources;

            timer.Interval = TimeSpan.FromMilliseconds(1);
            timer.Tick += Timer_Tick;


            Random ran = new Random();

            for (int i = 0; i < particleNumber; i++)
            {
                pos[i] = new Point(ran.Next(0, 1000), ran.Next(0, 800));
            }

            this.Unloaded += PerlinNoisePage_Unloaded;
            timer.Start();



        }

        private void PerlinNoisePage_Unloaded(object sender, RoutedEventArgs e)
        {
            timer.Stop();
            timer = null;
            canvas.RemoveFromVisualTree();
            canvas = null;
        }




        /// <summary>
        /// 流动
        /// </summary>
        void FliudAnimation()
        {

            int width = (int)canvas.ActualWidth;
            int height = (int)canvas.ActualHeight;
            float scale = 0.007f;

            Random ran = new Random();


            Color[] fliudColors = new Color[width * height];

            int[] pointNumber = new int[width * height];


            var listTask = PictureFilter.MultiThreading(particleNumber, (sx, ex) =>
            {

                for (int i = sx; i < ex; i++)
                {
                    var item = pos[i];


                    var noise = p.perlin(item.X * scale, item.Y * scale, 0);
                    double angle = noise * (2 * Math.PI);

                    double speed = 5;

                    double ox = Math.Cos(angle) * speed;
                    double oy = Math.Sin(angle) * speed;

                    Point point = new Point();
                    point.X = item.X + ox;
                    point.Y = item.Y + oy;

                    if (point.X < 0 || point.X >= width || point.Y < 0 || point.Y >= height)
                    {
                        pos[i] = new Point(ran.Next(0, width), ran.Next(0, height));
                    }
                    else

                    {
                        try
                        {


                            fliudColors[(int)point.X + (int)point.Y * width] = Colors.Orange;
                            //pointNumber[(int)point.X + (int)point.Y * width]++;

                        }
                        catch (Exception expection)
                        {

                        }
                        pos[i] = point;

                    }

                }
            });


            Task.WaitAll(listTask.Select(q => q.AsTask()).ToArray());

            //CanvasRenderTarget crt = new CanvasRenderTarget(canvas, width, height);

            //using (var ds = crt.CreateDrawingSession())
            //{



            //    for (int x = 0; x < width; x++)
            //    {
            //        for (int y = 0; y < height; y++)
            //        {
            //            var item = pointNumber[x + y * width];

            //            if (item > 1)
            //            {

            //                double r = (double)item;
            //                var noise = p.perlin(x * scale, y * scale, 0);
            //                double angle = noise * (2 * Math.PI) + (Math.PI / 2);

            //                Vector2 v1 = new Vector2((float)(x + r * Math.Cos(angle)), (float)(y + r * Math.Sin(angle)));
            //                Vector2 v2 = new Vector2(x + (x - v1.X), y + (y - v1.Y));
            //                ds.DrawLine(v1, v2, Colors.White);
            //            }



            //        }
            //    }
            //}

            Color[] layeredClouds = new Color[width * height];

            using (var ds = fliudRender.CreateDrawingSession())
            {
                ds.Clear(Colors.Black);

                //layeredClouds = PictureFilter.LayeredCloudsEffect(width, height, scale, 0, 0, scale* scale);

                //ds.DrawImage(CanvasBitmap.CreateFromColors(canvas, layeredClouds, width, height));

                CanvasBitmap bitmap = CanvasBitmap.CreateFromColors(canvas, fliudColors, width, height);
                ds.DrawImage(bitmap);

                //ds.DrawImage(bitmap);





            }




        }

        /// <summary>
        /// 圆形
        /// </summary>
        async void CircleAnimation()
        {
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {

                using (var ds = circleRender.CreateDrawingSession())
                {
                    ds.Clear(Colors.Transparent);
                    CanvasPathBuilder path = new CanvasPathBuilder(canvas);

                    ds.FillRectangle(new Rect(0, 0, 1000, 400), Color.FromArgb(128, 50, 50, 50));

                    float cx = 400;
                    float cy = 400;




                    float x = 0;
                    double r = 1d;

                    for (double i = 0; i < 360; i += 1)
                    {




                        float angle = (float)(i / 360d * (2 * Math.PI));





                        double lx = cx + r * Math.Cos(angle);
                        double ly = cy + r * Math.Sin(angle);

                        double sum = p.perlin(lx, ly, time);

                        double length = sum * 400;



                        lx = cx + length * Math.Cos(angle);
                        ly = cy + length * Math.Sin(angle);



                        if (i == 0)
                        {
                            path.BeginFigure((float)lx, (float)ly);
                        }
                        else
                        {
                            path.AddLine((float)lx, (float)ly);
                        }

                        ds.DrawCircle((float)lx, (float)ly, 2, Colors.Red);

                        //ds.DrawLine(cx, cy, lx, ly,Color.FromArgb(255,(byte)(r*255),(byte)(g*255),(byte)(b*255)));

                    }
                    path.EndFigure(CanvasFigureLoop.Open);
                    CanvasGeometry gemetry = CanvasGeometry.CreatePath(path);
                    ds.DrawGeometry(gemetry, Colors.Black);
                }
                canvas.Invalidate();
            });
        }

        double rox = 0;
        double roy = 0;

        double rcx = 0, rcy = 0;

        /// <summary>
        /// 丝带
        /// </summary>
         void RiddonAnimation()
        {
            float scale = 0.003f;
           
                if (canvas == null)
                    return;

                CanvasRenderTarget crt = new CanvasRenderTarget(canvas, (int)canvas.ActualWidth, (int)canvas.ActualHeight);
                using (var ds = crt.CreateDrawingSession())
                {
                    ds.Clear(Colors.Transparent);
                    CanvasPathBuilder path = new CanvasPathBuilder(canvas);
                    byte r = (byte)(p.perlin(ribbonFrameCount * scale) * 255);
                    byte g = (byte)(p.perlin(ribbonFrameCount * scale + 200) * 255);
                    byte b = (byte)(p.perlin(ribbonFrameCount * scale + 300) * 255);

                    double ra = p.perlin(rox) * 200;
                    Color stroke = Color.FromArgb(255, r, g, b);
                    for (double i = 0; i < 360; i += 1)
                    {
                        float angle = (float)(i / 360d * (2 * Math.PI));
                        Vector2 pv = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
                        double radius = p.perlin(rox + pv.X, roy + pv.Y) * ra;
                        pv.X = (float)(pv.X * radius);
                        pv.Y = (float)(pv.Y * radius);
                        double lx = rcx + pv.X;
                        double ly = rcy + pv.Y;
                        if (i == 0)
                        {
                            path.BeginFigure((float)lx, (float)ly);
                        }
                        else
                        {
                            path.AddLine((float)lx, (float)ly);
                        }
                    }

                    path.EndFigure(CanvasFigureLoop.Closed);
                    CanvasGeometry gemetry = CanvasGeometry.CreatePath(path);
                    ds.DrawGeometry(gemetry, stroke);
                }
                ribbonFrameCount++;
                rox += 0.004;
                roy += 0.004;
                rcx++;
                using (var ds = ribbonRender.CreateDrawingSession())
                {
                    if (rcx > canvas.ActualWidth)
                    {
                        rcx = 0;
                        ds.Clear(Colors.Black);
                    }
                    else
                    {
                        ds.DrawImage(crt);

                    }

                }
                canvas.Invalidate();
         
        }

        double sr = 0;

        /// <summary>
        /// 太阳火
        /// </summary>
         void SunFireAnimation()
        {
            float scale = 0.005f;

           
                CanvasRenderTarget crt = new CanvasRenderTarget(canvas, (int)canvas.ActualWidth, (int)canvas.ActualHeight);

                using (var ds = crt.CreateDrawingSession())
                {
                    ds.Clear(Colors.Transparent);
                    CanvasPathBuilder path = new CanvasPathBuilder(canvas);







                    double ra = p.perlin(rox) * 200;

                    Color stroke = Color.FromArgb(128, 255, 64, 8);

                    for (double i = 0; i < 360; i += 1)
                    {

                        float angle = (float)(i / 360d * (2 * Math.PI));


                        Vector2 pv = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));



                        double radius = p.perlin(cx + sr * scale + pv.X, cy + sr * scale + pv.Y) * sr;


                        pv.X = (float)(pv.X * radius);
                        pv.Y = (float)(pv.Y * radius);

                        double lx = cx + pv.X;
                        double ly = cy + pv.Y;



                        if (i == 0)
                        {
                            path.BeginFigure((float)lx, (float)ly);
                        }
                        else
                        {
                            path.AddLine((float)lx, (float)ly);
                        }



                    }

                    path.EndFigure(CanvasFigureLoop.Closed);

                    CanvasGeometry gemetry = CanvasGeometry.CreatePath(path);
                    ds.DrawGeometry(gemetry, stroke);

                }

                sr += 0.5;

                CanvasBitmap bitmap = CanvasBitmap.CreateFromColors(canvas, sunFireRender.GetPixelColors(), (int)sunFireRender.Size.Width, (int)sunFireRender.SizeInPixels.Height, 96f);

                using (var ds = sunFireRender.CreateDrawingSession())
                {
                    if (sr > canvas.ActualWidth)
                    {
                        sr = 0;
                        ds.Clear(Colors.Black);
                    }
                    else
                    {
                        BlendEffect be = new BlendEffect()
                        {
                            Background = bitmap,
                            Foreground = crt,
                            Mode = BlendEffectMode.Screen
                        };
                        ds.DrawImage(be);

                        //ds.DrawImage(crt);

                    }

                }


                canvas.Invalidate();
            ribbonFrameCount++;
        }

        /// <summary>
        /// 线动画
        /// </summary>
        void LineAnimation()
        {
            double x = perlin.perlin(time, 0, 0);
            double y = perlin.perlin(5 + time, 0, 0);

            Point center = new Point(x, y);

            double length = perlin.perlin(10 + time, 0, 0);
            double angle = perlin.perlin(15 + time, 0, 0);

            CanvasRenderTarget crt = new CanvasRenderTarget(canvas, 1000, 1000);

            using (var ds = crt.CreateDrawingSession())
            {
                double cx = center.X * 1000;
                double cy = center.Y * 1000;

                double l = length * 800;

                double a = angle * (8 * Math.PI);
                double x1 = cx + l / 2 * Math.Cos(a);
                double y1 = cy + l / 2 * Math.Sin(a);

                double x2 = cx + (cx - x1);
                double y2 = cy + (cy - y1);

                ds.DrawLine((float)x1, (float)y1, (float)x2, (float)y2, Colors.Black);
                //ds.FillCircle((float)cx, (float)cy, 3f, Colors.Red);
            }

            if (length >= 0.8)
            {
                int count = 1;
            }

            if (listRender.Count - 1 == 300)
            {
                listRender.RemoveAt(0);
            }

            listRender.Add(crt);


            canvas.Invalidate();
        }

        private void Timer_Tick(object sender, object e)
        {
            switch (type)
            {
                case AnimationType.None:
                    break;
                case AnimationType.Line:
                    LineAnimation();
                    break;
                case AnimationType.Cricle:
                    CircleAnimation();
                    break;
                case AnimationType.Fliud:
                    FliudAnimation();
                    break;
                case AnimationType.Clouds:
                    break;
                case AnimationType.Ribbon:
                    RiddonAnimation();
                    break;
                case AnimationType.SunFire:
                    SunFireAnimation();
                    break;
            }

            time += 0.05;
            if (canvas == null)
                return;

            canvas.Invalidate();
        }

        private void Canvas_CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args)
        {


            Initial();

            circleRender = new CanvasRenderTarget(sender, 1000, 1000);
            fliudRender = new CanvasRenderTarget(sender, 1000, 800);
            ribbonRender = new CanvasRenderTarget(sender, (int)canvas.ActualWidth, (int)canvas.ActualHeight);
            using (var ds = ribbonRender.CreateDrawingSession())
            {
                ds.Clear(Colors.Black);
            }

            sr = 1;

            sunFireRender = new CanvasRenderTarget((CanvasControl)sender, (int)canvas.ActualWidth, (int)canvas.ActualHeight);
            using (var ds = sunFireRender.CreateDrawingSession())
            {
                ds.Clear(Colors.Black);
            }
        }

        private void canvas_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            try
            {

                cx = canvas.ActualWidth / 2;
                cy = canvas.ActualHeight / 2;

                rcx = 0;
                rcy = canvas.ActualHeight / 2;

                ribbonRender = new CanvasRenderTarget((CanvasControl)sender, (int)canvas.ActualWidth, (int)canvas.ActualHeight);
                using (var ds = ribbonRender.CreateDrawingSession())
                {
                    ds.Clear(Colors.Black);
                }

                sr = 1;

                sunFireRender = new CanvasRenderTarget((CanvasControl)sender, (int)canvas.ActualWidth, (int)canvas.ActualHeight);
                using (var ds = sunFireRender.CreateDrawingSession())
                {
                    ds.Clear(Colors.Black);
                }
            }
            catch
            {

            }
        }


        double x = 0;

        void Initial()
        {

            Puzzle puzzle = new Puzzle();
            puzzle.X = x;

            CanvasRenderTarget crt = new CanvasRenderTarget(canvas, 5000, 100);
            using (var ds = crt.CreateDrawingSession())
            {
                ds.Clear(Colors.BlueViolet);
                //CanvasPathBuilder path = new CanvasPathBuilder(canvas);
                //path.BeginFigure(new System.Numerics.Vector2(0, 0));

                int dx = 0;
                for (double i = sx; i < ex; i += 0.1)
                {

                    double sum = p.perlin(i, 0, 0);


                    Vector2 point = new Vector2((float)dx, (float)sum * 100f);

                    ds.DrawLine(new Vector2(dx, 100), point, Colors.Black);

                    //path.AddLine(point);


                    dx += 5;

                }


                //path.EndFigure(CanvasFigureLoop.Open);
                //CanvasGeometry gemetry = CanvasGeometry.CreatePath(path);
                //ds.DrawGeometry(gemetry, Colors.Black, 2f);
            }
            puzzle.Render = crt;
            listPuzzle.Add(puzzle);


            sx = ex;
            ex = ex + 1000;
            x = x + 5000;
            maxWidth += 5000;


        }


        private void canvas_Draw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args)
        {

            using (var ds = args.DrawingSession)
            {


                Function.DrawGridGraphics(args.DrawingSession, 50);





                switch (type)
                {
                    case AnimationType.Clouds:

                        var layerClouds = PictureFilter.LayeredCloudsEffect((int)canvas.ActualWidth, (int)canvas.ActualHeight, 0.0015, 0, 0, time);
                        ds.DrawImage(CanvasBitmap.CreateFromColors(canvas, layerClouds, (int)canvas.ActualWidth, (int)canvas.ActualHeight));

                        break;

                    case AnimationType.Fliud:
                        ds.DrawImage(fliudRender);

                        break;

                    case AnimationType.Cricle:
                        ds.DrawImage(circleRender);

                        break;
                    case AnimationType.Line:
                        float i = 1;

                        foreach (var item in listRender)
                        {
                            OpacityEffect ae = new OpacityEffect()
                            {
                                Source = item,
                                Opacity = i / (float)(listRender.Count)
                            };

                            ds.DrawImage(ae);

                            i++;

                        }
                        break;
                    case AnimationType.Ribbon:
                        ds.DrawImage(ribbonRender);
                        break;

                    case AnimationType.SunFire:
                        ds.DrawImage(sunFireRender);
                        break;

                }




            }
        }


        private void canvas_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
        {



            currentX -= e.Delta.Translation.X;

            double lx = listPuzzle.Last().X;

            if (lx < currentX + canvas.ActualWidth)
            {
                Initial();

            }

            canvas1.Invalidate();
        }

        private void startAnimation_Click(object sender, RoutedEventArgs e)
        {
            type = AnimationType.Line;
        }



        private void startCircleAnimation_Click(object sender, RoutedEventArgs e)
        {
            type = AnimationType.Cricle;

        }

        private void startFluidAnimation_Click(object sender, RoutedEventArgs e)
        {
            type = AnimationType.Fliud;

        }

        private void clouds_Click(object sender, RoutedEventArgs e)
        {
            type = AnimationType.Clouds;

        }

        private void canvas_Draw1(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args)
        {
            using (var ds = args.DrawingSession)
            {





                foreach (var item in listPuzzle)
                {
                    if (item.X <= currentX && currentX < item.X + 5000)
                    {
                        ds.DrawImage(item.Render, (float)-Math.Abs(currentX) % 5000, 0);

                    }
                    if (item.X >= currentX)
                    {
                        ds.DrawImage(item.Render, (float)(5000 - (currentX % 5000)), 0);

                        break;
                    }

                }
            }
        }

        private void sunFire_Click(object sender, RoutedEventArgs e)
        {
            type = AnimationType.SunFire;

        }

        private void ribbon_Click(object sender, RoutedEventArgs e)
        {
            type = AnimationType.Ribbon;

        }


    }
    enum AnimationType
    {

        None,
        Line,
        Cricle,
        Fliud,
        Clouds,
        Ribbon,
        SunFire

    }

    public class Puzzle
    {
        public CanvasRenderTarget Render { get; set; }

        public double X { get; set; }
        public double Y { get; set; }
    }

}
